Magma
is a hardware construction language written in Python 3
. The central abstraction in Magma
is a Circuit
, which is analagous to a verilog module. A circuit is a set of functional units that are wired together.
Magma
is designed to work with Mantle
, a library of hardware building blocks including logic and arithmetic units, registers, memories, etc.
The Loam
system builds upon the Magma
Circuit
abstraction to represent parts and boards. A board consists of a set of parts that are wired together. Loam
makes it is easy to setup a board such as the Lattice IceStick.
In this tutorial, we will be using the Lattice IceStick. This breakout board contains a ICE40HX FPGA with 1K 4-input LUTs. The board has several useful peripherals including an FTDI USB interface with an integrated JTAG interface which is used to program the FPGA and a USART which is used to communicate with the host. The board also contains 5 LEDs, a PMOD interface, and 2 10-pin headers (J1 and J3). The 10-pin headers bring out 8 GPIO pins, as well as power and ground. This board is inexpensive ($25), can be plugged into the USB port on your laptop, and, best of all, can be programmed using an open source software toolchain.
Additional information about the IceStick Board can be found in the IceStick Programmers Guide
In [1]:
import magma as m
m.set_mantle_target("ice40")
The next step is to setup the IceStick board. We import the class IceStick
from Loam
.
We then create an instance of an IceStick
.
This board instance has member variables
that store the configuration of all the parts on the board.
The blink program will use the Clock and the LED D5.
Turning on the Clock and the LED D5 sets up the build environment
to use the associated ICE40 GPIO pins.
In [2]:
from loam.boards.icestick import IceStick
# Create an instance of an IceStick board
icestick = IceStick()
# Turn on the Clock
# The clock must turned on because we are using a synchronous counter
icestick.Clock.on()
# Turn on the LED D5
icestick.D5.on();
Now that the IceStick setup is done,
we create a main
program that runs on the Lattice ICE40 FPGA.
This main program becomes the top level module.
We create a simple circuit inside main
.
The circuit has a a 22-bit counter wired to D5.
The crystal connected to the ICE40 has a frequency of 12 Mhz.
so the counter will increment at that rate.
Wiring the most-significant bit of the counter to D5
will cause the LED to blink roughly 3 times per second.
D5
is accessible via main
.
In a similar way, the output of the counter is accesible via counter.O
,
and since this an array of bits we can access the MSB using Python's standard list indexing syntax.
In [3]:
from mantle import Counter
N = 22
# Define the main Magma Circuit on the FPGA on the IceStick
main = icestick.DefineMain()
# Instance a 22-bit counter
counter = Counter(N)
# Wire bit 21 of the counter's output to D5.
main.D5 <= counter.O[N-1]
# End main
m.EndDefine()
We then compile the program to verilog. This step also creates a PCF (physical constraints file).
In [4]:
m.compile('build/blink', main)
Now we run the open source tools for the Lattice ICE40.
yosys
synthesizes the input verilog file (blink.v
)
to produce an output netlist (blink.blif
).
arachne-pnr
runs the place and router and generates the bitstream as a text file.
icepack
creates a binary bitstream file that can be downloaded to the FPGA. iceprog
uploads the bitstream to the device. Once the device has been programmed, you should see the center, green LED blinking.
In [5]:
%%bash
cd build
yosys -q -p 'synth_ice40 -top main -blif blink.blif' blink.v
arachne-pnr -q -d 1k -o blink.txt -p blink.pcf blink.blif
icepack blink.txt blink.bin
#iceprog blink.bin
You can view the verilog file generated by Magma
.
In [6]:
%cat build/blink.v
Notice that the top-level module contains two arguments (ports),
D5
and CLKIN
.
D5
has been configured as an output,
and CLKIN
as an input.
The mapping from these named arguments to pins is contained in the PCF (physical constraint file).
In [7]:
%cat build/blink.pcf
D5
is connected to pin 95 and CLKIN
is connected to pin 21.